﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Xml;
using System.Xml.Serialization;
using SharpDX.Multimedia;

namespace MikadoShooter
{
    public static class SoundIO
    {
        private const string SoundPack = @".\Context\sounds.pak";

        public static void LoadSound(eSoundname soundname, ref Dictionary<eSoundname, AudioCache> sounds, SoundElement soundElement, string key, string iv)
        {
            if (sounds.ContainsKey(soundname) || !File.Exists(SoundPack) || soundElement == null)
                return;

            using (AesCryptoServiceProvider aesCrypto = new AesCryptoServiceProvider())
            {
                aesCrypto.Key = key.StringToBytes();
                aesCrypto.IV = iv.StringToBytes();
                aesCrypto.Mode = CipherMode.CFB;
                aesCrypto.Padding = PaddingMode.Zeros;

                using (FileStream fileStream = new FileStream(SoundPack, FileMode.Open))
                {
                    using (CryptoStream cryptoStream = new CryptoStream(fileStream, aesCrypto.CreateDecryptor(), CryptoStreamMode.Read))
                    {
                        //Read and decrypt
                        byte[] bytes = new byte[soundElement.Length];
                        fileStream.Position = soundElement.Start;
                        cryptoStream.Read(bytes, 0, soundElement.Length);

                        //Compare hash
                        using (MD5 md5 = MD5.Create())
                        {
                            if (md5.ComputeHash(bytes).BytesToString() != soundElement.Hash)
                            {
                                Debug.WriteLine("Invalid hash " + soundElement.Name);
                                return;
                            }
                        }

                        //Add to Dictionary
                        using (SoundStream soundstream = new SoundStream(new MemoryStream(bytes)))
                        {
                            Debug.WriteLine("Loading sound " + soundElement.Name);
                            sounds.Add(soundname, new AudioCache(soundstream.ToDataStream(), soundstream.Length, soundstream.DecodedPacketsInfo, soundstream.Format));
                        }
                    }
                }
            }
        }

        public static SoundFile LoadSoundXML()
        {
            SoundFile soundFile = null;
            Stream stream = default(Stream);
           
            try
            {
                if ((stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MikadoShooter.Context.sound.xml")) != null)
                {
                    using (XmlReader xml = XmlReader.Create(stream))
                    {
                        soundFile = (SoundFile)new XmlSerializer(typeof(SoundFile)).Deserialize(xml);
                    }
                }
            }
            catch
            {
                return soundFile;
            }
            finally
            {
                if (stream != null)
                    stream.Dispose();
            }
            return soundFile;
        }


        private static string BytesToString(this byte[] input)
        {
            return BitConverter.ToString(input).Replace("-", "").ToLower();
        }

        private static byte[] StringToBytes(this string input)
        {
            input = input.ToLower();
            byte[] array = new byte[input.Length / 2];

            for (int i = 0, j = 0; i < array.Length; i++, j += 2)
            {
                array[i] = Convert.ToByte(string.Concat(input[j], input[j + 1]).ToLower(), 16);
            }

            return array;
        }
    }
}